<template>
  <div class="dv-scroll-board">
    <div
        class="header"
        v-if="state.header.length && state.option"
        :style="`background-color: ${state.option.headerBGC};`"
    >
      <div
          class="header-item"
          v-for="(headerItem, i) in state.header"
          :key="`${headerItem}${i}`"
          :style="`
        height: ${state.option.headerHeight}px;
        line-height: ${state.option.headerHeight}px;
        width: ${state.widths[i]}px;
      `"
          :align="state.aligns[i]"
          v-html="headerItem"
      />
    </div>

    <div
        v-if="state.option"
        class="rows"
        :style="`height: ${height - (state.header.length ? state.option.headerHeight : 0)}px;`"
    >
      <div
          class="row-item"
          v-for="(row, ri) in state.rows"
          :key="`${row.toString()}${row.scroll}`"
          :style="`
        height: ${state.heights[ri]}px;
        line-height: ${state.heights[ri]}px;
        background-color: ${state.option[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']};
      `"
      >
        <div
            class="ceil"
            v-for="(ceil, ci) in row.ceils"
            :key="`${ceil}${ri}${ci}`"
            :style="`width: ${state.widths[ci]}px;`"
            :align="state.aligns[ci]"
            v-html="ceil"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {onUnmounted, reactive, watch, onMounted, computed} from 'vue'
import {copyDefinedProperties} from "../../../utils/copy.ts";
import merge from 'lodash/merge'
defineOptions({
  name: 'TableScroll'
})
const props = defineProps(['option']);
const state = reactive({
  option: {
    /**
     * @description Board header
     * @type {Array<String>}
     * @default header = []
     * @example header = ['column1', 'column2', 'column3']
     */
    header: ['列1', '列2', '列3','列4','列5','列6'],
    /**
     * @description Board dataset
     * @type {Array<Array>}
     * @default dataset = []
     */
    dataset: [
      ["行1列1", "行1列2", "行1列3","行1列4", "行1列5", "行1列6"],
    ],
    /**
     * @description Row num
     * @type {Number}
     * @default rowNum = 5
     */
    rowNum: 5,
    /**
     * @description Header background color
     * @type {String}
     * @default headerBGC = '#00BAFF'
     */
    headerBGC: 'rgba(0,0,0,0)',
    /**
     * @description Odd row background color
     * @type {String}
     * @default oddRowBGC = '#003B51'
     */
    oddRowBGC: 'rgba(0,0,0,0)',
    /**
     * @description Even row background color
     * @type {String}
     * @default evenRowBGC = '#003B51'
     */
    evenRowBGC: 'rgba(0,0,0,0)',
    /**
     * @description Scroll wait time
     * @type {Number}
     * @default waitTime = 2
     */
    waitTime: 2,
    /**
     * @description Header height
     * @type {Number}
     * @default headerHeight = 35
     */
    headerHeight: 35,
    /**
     * @description Column width
     * @type {Array<Number>}
     * @default columnWidth = []
     */
    columnWidth: [30, 100, 100],
    /**
     * @description Column align
     * @type {Array<String>}
     * @default align = []
     * @example align = ['left', 'center', 'right']
     */
    align:['center', 'center', 'center', 'center','center','center'],
    /**
     * @description Show index
     * @type {Boolean}
     * @default index = false
     */
    index: false,
    /**
     * @description index Header
     * @type {String}
     * @default indexHeader = '#'
     */
    indexHeader: '#',
    /**
     * @description Carousel type
     * @type {String}
     * @default carousel = 'single'
     * @example carousel = 'single' | 'page'
     */
    carousel: 'single',
    /**
     * @description Pause scroll when mouse hovered
     * @type {Boolean}
     * @default hoverPause = true
     * @example hoverPause = true | false
     */
    hoverPause: true,
    height:20,
    width:50,
    left:26.5,
    top:89.5,
  },
  header: [],
  rowsData: [],
  rows: [
    {
      ceils: [],
      rowIndex: 0,
      scroll: 0
    },
  ],
  widths: [],
  heights: [0],
  avgHeight: 0,
  aligns: [],
  animationIndex: 0,
  animationHandler: 0,
  updater: 0,
  needCalc: false,
  window:{
    height:1700,
    width:800,
  },
})
onMounted(()=>{
  setting()
})
const left=computed(()=>`${(state.option.left/100)*state.window.width}px`)
const top=computed(()=>`${(state.option.top/100)*state.window.height}px`)
const height=computed(()=>`${(state.option.height/100)*state.window.height}px`)
const width=computed(()=>`${(state.option.width/100)*state.window.width}px`)

function setting(){
  if(props.option!==undefined){
    // console.log(props.option)
    copyDefinedProperties(props.option,state.option)
  }
  state.window={
    width: document.body.clientWidth,
    height: document.body.clientHeight
  }
}
watch(()=>props.option,(newValue,oldValue)=>{
  // console.log('workOrder变化了',newValue,oldValue)
  setting()
},{immediate:true,deep:true})
window.addEventListener('resize',()=>{
  // console.log("width,height",document.body.clientWidth,document.body.clientHeight)
  state.window={
    width: document.body.clientWidth,
    height: document.body.clientHeight
  }
})
const calcData = () => {
  setting()
  calcHeaderData()
  calcRowsData()
  calcWidths()
  calcHeights()
  calcAligns()
  animation(true)
}

onMounted(() => {
  calcData()
  onRestart()
})



const calcHeaderData = () => {
  let { header, index, indexHeader } = state.option
  if (!header.length) {
    state.header = []
    return
  }
  header = [...header]
  if (index) header.unshift(indexHeader)
  state.header = header
}

const calcRowsData = () => {
  let { dataset, index, headerBGC, rowNum } = state.option
  if (index) {
    dataset = dataset.map((row: any, i: number) => {
      row = [...row]
      const indexTag = `<span class="index" style="background-color: ${headerBGC};border-radius: 3px;padding: 0px 3px;">${
          i + 1
      }</span>`
      row.unshift(indexTag)
      return row
    })
  }
  dataset = dataset.map((ceils: any, i: number) => ({ ceils, rowIndex: i }))
  const rowLength = dataset.length
  if (rowLength > rowNum && rowLength < 2 * rowNum) {
    dataset = [...dataset, ...dataset]
  }
  dataset = dataset.map((d: any, i: number) => ({ ...d, scroll: i }))

  state.rowsData = dataset
  state.rows = dataset
}

const calcWidths = () => {
  const { option, rowsData } = state
  const { columnWidth, header } = option
  const usedWidth = columnWidth.reduce((all: any, ws: number) => all + ws, 0)
  let columnNum = 0
  if (rowsData[0]) {
    columnNum = (rowsData[0] as any).ceils.length
  } else if (header.length) {
    columnNum = header.length
  }
  const avgWidth = ((state.option.width/100)*state.window.width - usedWidth) / (columnNum - columnWidth.length)
  const widths = new Array(columnNum).fill(avgWidth)
  state.widths = merge(widths, columnWidth)
}

const calcHeights = (onresize = false) => {
  const { option, header } = state
  // console.log(state)
  const { headerHeight, rowNum, dataset } = option
  let allHeight = (state.option.height/100)*state.window.height
  if (header.length) allHeight -= headerHeight
  const avgHeight = allHeight / rowNum
  state.avgHeight = avgHeight
  if (!onresize) state.heights = new Array(dataset.length).fill(avgHeight)
}

const calcAligns = () => {
  const { header, option } = state

  const columnNum = header.length

  let aligns = new Array(columnNum).fill('left')

  const { align } = option

  state.aligns = merge(aligns, align)
}

const animation = async (start = false) => {
  const { needCalc } = state

  if (needCalc) {
    calcRowsData()
    calcHeights()
    state.needCalc = false
  }
  let { avgHeight, animationIndex, option, rowsData, updater } = state
  const { waitTime, carousel, rowNum } = option

  const rowLength = rowsData.length
  if (rowNum >= rowLength) return
  if (start) {
    await new Promise(resolve => setTimeout(resolve, waitTime * 1000))
    if (updater !== state.updater) return
  }
  const animationNum = carousel === 'single' ? 1 : rowNum
  let rows = rowsData.slice(animationIndex)
  rows.push(...rowsData.slice(0, animationIndex))
  state.rows = rows.slice(0, carousel === 'page' ? rowNum * 2 : rowNum + 1)
  state.heights = new Array(rowLength).fill(avgHeight)
  await new Promise(resolve => setTimeout(resolve, 300))
  if (updater !== state.updater) return
  state.heights.splice(0, animationNum, ...new Array(animationNum).fill(0))
  animationIndex += animationNum
  const back = animationIndex - rowLength
  if (back >= 0) animationIndex = back
  state.animationIndex = animationIndex
  state.animationHandler = setTimeout(animation, waitTime * 1000 - 300) as any
}

const stopAnimation = () => {
  state.updater = (state.updater + 1) % 999999
  if (!state.animationHandler) return
  clearTimeout(state.animationHandler)
}

const onRestart = async () => {
  try {
    if (!state.option) return
    stopAnimation()
    calcData()
  } catch (error) {
    console.log(error)
  }
}

// watch(
//     () => w.value,
//     () => {
//       onRestart()
//     }
// )
//
// watch(
//     () => h.value,
//     () => {
//       onRestart()
//     }
// )
//
// 数据更新
watch(
    () => props.option,
    () => {
      onRestart()
    },
    { deep: true }
)


onUnmounted(() => {
  stopAnimation()
})
</script>

<style scoped>
.dv-scroll-board {
  //position: relative;
  //width: 100%;
  //height: 100%;
  z-index: 99999;
  position: absolute;
  left:v-bind(left);
  top:v-bind(top);
  width: v-bind(width);
  height: v-bind(height);
  color: #fff;

  .text {
    padding: 0 10px;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .header {
    display: flex;
    flex-direction: row;
    font-size: 15px;

    .header-item {
      transition: all 0.3s;
    }
  }

  .rows {
    overflow: hidden;

    .row-item {
      display: flex;
      font-size: 14px;
      transition: all 0.3s;
      overflow: hidden;
    }
  }
}
</style>
